#include "llt.h"

#include <x_config.h>
#include <k_task.h>

#ifdef CONFIG_TASK_CREATE_HOOK
extern int task_create_hook_add(task_create_pfn);
extern int task_create_hook_del(task_create_pfn pfn);
#endif
#ifdef CONFIG_TASK_DELETE_HOOK
extern int task_delete_hook_add(task_delete_pfn pfn);
extern int task_delete_hook_del(task_delete_pfn);
#endif
#ifdef CONFIG_TASK_SWITCH_HOOK
extern int task_switch_hook_add(task_switch_pfn pfn);
extern int task_switch_hook_del(task_switch_pfn);
#endif

static __unused int __create_hook(task_id task)
{
    kprintf("created %s\n", task->name);
    return 0;
}

static __unused void __delete_hook(task_id task)
{
    kprintf("deleting %s\n", task->name);
}

static __unused void __switch_hook(task_id old, task_id new)
{
    kprintf("%s -> %s\n", new->name, old->name);
}

/** test task hook interfaces */

// task_delete_hook_add, task_switch_hook_add like this
void test_task_create_hook_add(void **state)
{
#ifdef CONFIG_TASK_CREATE_HOOK
    int i = 0;

    for (i = 0; i < CONFIG_NR_TASK_CREATE_HOOK_SLOTS; ++i) {
        assert_int_equal(0, task_create_hook_add(__create_hook));
    }
    assert_int_equal(-1, task_create_hook_add(__create_hook));

    for (i = CONFIG_NR_TASK_CREATE_HOOK_SLOTS / 2; i > 0; --i) {
        assert_int_equal(0, task_create_hook_del(__create_hook));
    }
    for (i = CONFIG_NR_TASK_CREATE_HOOK_SLOTS / 2 + 1; i < CONFIG_NR_TASK_CREATE_HOOK_SLOTS; ++i) {
        assert_int_equal(0, task_create_hook_del(__create_hook));
    }
    if (CONFIG_NR_TASK_CREATE_HOOK_SLOTS > 0) {
        assert_int_equal(0, task_create_hook_del(__create_hook));
    }
#endif
}

static void __test_hook_init(void)
{
#ifdef CONFIG_TASK_CREATE_HOOK
    task_create_hook_add(__create_hook);
#endif
#ifdef CONFIG_TASK_DELETE_HOOK
    task_delete_hook_add(__delete_hook);
#endif
#ifdef CONFIG_TASK_SWITCH_HOOK
    task_switch_hook_add(__switch_hook);
#endif
}

static void __test_hook_exit(void)
{
#ifdef CONFIG_TASK_CREATE_HOOK
    task_create_hook_del(__create_hook);
#endif
#ifdef CONFIG_TASK_DELETE_HOOK
    task_delete_hook_del(__delete_hook);
#endif
#ifdef CONFIG_TASK_SWITCH_HOOK
    task_switch_hook_del(__switch_hook);
#endif
}

static void task_1(void)
{
    task_delay(2);
}

static void task_2(void)
{
    task_delay(3);
}

void test_task_hook_demo(void **state)
{
    __test_hook_init();

    task_spawn("task_1", 18, 0, 0x400, (int (*)(uintptr_t))task_1, 0);
    task_spawn("task_2", 19, 0, 0x400, (int (*)(uintptr_t))task_2, 0);

    task_delay(5);

    __test_hook_exit();
}

/** test entry */

void test_hook(struct tester_case *caser)
{
    UnitTest tests[] = {
        unit_test(test_task_create_hook_add),
        unit_test(test_task_hook_demo),
    };

    caser->stats->totals = sizeof(tests) / sizeof(tests[0]);
    caser->stats->fails = run_tests(tests);
}

TESTER_CASE_DEF("test_hook", test_hook, NULL, NULL, 0);
